<template>
  <el-select ref="selectRef"
             v-model="selectedIds"
             v-bind="$attrs"
             :filter-method="selectFilterMethod"
             @visible-change="selectVisibleChangeHandler"
             @focus="focusHandler"
             @change="selectChangeHandler">
    <el-option disabled class="tree-option" :value="null">
      <el-tree :data="treeData"
               class="tree"
               ref="treeRef"
               v-bind="treeOptions"               
               :node-key="treeOptions&&treeOptions.nodeKey||commonProps.id"
               :props="{
                         id: commonProps.id,
                         label: commonProps.label,
                         children: commonProps.children
                     }"
               :filterNodeMethod="filterNodeMethod"
               :show-checkbox="multiple"
               default-expand-all
               :highlight-current="!multiple"
               :expand-on-click-node="multiple || leafOnly"
               @node-expand="nodeExpandHandler"
               @node-collapse="nodeCollapseHandler"
               @node-click="treeClickHandler"
               @check="treeCheckHandler"/>
    </el-option>
    <!--  将其余的选型隐藏掉  -->
    <el-option v-for="item in plainData.filter(e=> multiple? e.isLeaf : ( leafOnly? e.isLeaf:true))"
               :key="item[commonProps.id]"
               :value="item[commonProps.id]"
               :label="item[commonProps.label]"
               v-show="false"
    />
  </el-select>
</template>
<script>
import Vue from "vue";

export default {
  name: 'TreeSelect',
  props: {
    value: {
      type: [Array, String, Number],
    },
    data: {
      type: Array,
      default: () => []
    },
    leafOnly: Boolean,
    treeOptions: {
      type: Object,
      default: () => ({})
    },
  },
  data: () => ({
    treeData: [],
    plainData: [],
    selectedIds: [],
    lastHighlightNodeId: undefined,
    panelScrollTop: 0,
  }),
  watch: {
    data: {
      handler() {
        this.treeData = this.data
        this.plainData = this.getPlainTreeData(this.data)
        this.panelScrollTop = 0
      },
      deep: true,
      immediate: true
    },
    value: {
      handler() {
        console.log('this.commonProps', this.commonProps);
        if (this.multiple) {
          // 多选
          this.selectedIds = JSON.parse(JSON.stringify(this.value))
          this.$nextTick(() => {
            this.$refs.treeRef.setCheckedKeys(this.value.filter(id => this.plainData.find(item => item.id === id)?.isLeaf))
          })
        } else {
          // 单选
          // 设置选中的ID为当前值
          this.selectedIds = this.value
          // 如果只允许选择叶子节点且当前选中的不是叶子节点
          if (this.leafOnly && !this.plainData.find(e => e[this.commonProps.id] === this.value)?.isLeaf) {
            // 清除高亮节点
            this.lastHighlightNodeId = undefined
            this.$nextTick(() => {
              // 清除树组件当前选中项
              this.$refs.treeRef.setCurrentKey(undefined)
            })
          } else {
            // 设置高亮节点为当前值
            const value = this.value === undefined ? undefined : this.value
            this.lastHighlightNodeId = value
            this.$nextTick(() => {
              // 设置树组件当前选中项
              this.$refs.treeRef.setCurrentKey(value)
            })
          }
        }
      },
      deep: true,
      immediate: true
    },

  },
  computed: {
    commonProps() {
      return {
        id: this.$attrs?.props?.id || 'id',
        label: this.$attrs?.props?.label || 'title',
        children: this.$attrs?.props?.children || 'children'
      }
    },
    multiple() {
      return Object.keys(this.$attrs).includes('multiple') && this.$attrs.multiple !== false
    }
  },
  methods: {
    getPlainTreeData(treeData, result = []) { // 初始化下拉菜单本身的选项
      treeData.forEach(e => {
        const current = {
          [this.commonProps.id]: e[this.commonProps.id],
          [this.commonProps.label]: e[this.commonProps.label]
        }
        result.push(current)
        if (e[this.commonProps.children]?.length) {
          this.getPlainTreeData(e[this.commonProps.children], result)
        } else {
          current.isLeaf = true
        }
      })
      return result
    },
    treeClickHandler(val, node) {// 树选中节点（单选时）
      if (!this.multiple) {
        if (this.leafOnly && !node.isLeaf) {
          this.$refs.treeRef.setCurrentKey(this.lastHighlightNodeId)
          return
        }
        this.lastHighlightNodeId = val.id

        this.selectedIds = val[this.commonProps.id]
        this.$refs.selectRef.handleClose();
        this.$emit('input', this.selectedIds)
        this.$emit('change', this.selectedIds)
      }
    },
    treeCheckHandler() {// 树选中节点（多选时）
      if (this.multiple) {
        this.selectedIds = this.$refs.treeRef.getCheckedKeys(true)
        this.$emit('input', [...this.selectedIds])
        this.$emit('change', [...this.selectedIds])
      }
    },
    selectChangeHandler(values) { // 下拉选中内容改变时
      if (this.multiple) {
        this.$refs.treeRef.setCheckedKeys(values)
      } else {
        this.lastHighlightNodeId = values || undefined
        this.$refs.treeRef.setCurrentKey(values || undefined)
      }
      this.$emit('input', values)
    },
    nodeCollapseHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper');
      }, 10)
    },
    nodeExpandHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper');
      }, 10)
    },
    // 筛选功能相关
    selectFilterMethod(val) {
      this.$refs.treeRef.filter(val)
    },
    filterNodeMethod(val, data) {
      if (!val) {
        return true
      }
      return String(data.name).toLowerCase().includes(String(val).toLowerCase());
    },
    selectVisibleChangeHandler(isVisible) {
      if (!isVisible) {
        this.panelScrollTop = this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTop
      }
      setTimeout(() => {
        this.$refs.treeRef.filter()
      }, 100)
    },
    focusHandler() {
      setTimeout(() => {
        this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTo({top: this.panelScrollTop || 0})
      })
    }
  }
}
</script>

<style scoped>
.tree-option {
  width: 100%;
  line-height: 0;
  padding: 0 !important;
  height: 100%;
  overflow: auto;
}

.tree {
  font-weight: normal;
  width: 100%;
}
:deep(.el-tree-node__content) {
  padding-right: 10px;
  height: 36px;
  line-height: 36px;
}

:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
  font-weight: bold;
}

:deep(.el-tree-node__children) {
  width: 0;
  overflow: hidden;
}

:deep(.el-tree-node__children[aria-expanded='true']) {
  position: relative;
  width: 100%;
}

:deep(.el-select-dropdown__list > *) {
  display: none;
}

:deep(.el-select-dropdown__list > *:first-child) {
  display: block;
}
</style>
